package org.jdsm.flow.core.users.dao;

import org.jdsm.flow.core.base.dao.IGenericDao;
import org.jdsm.flow.core.users.IGroup;
import org.jdsm.flow.core.users.IRole;
import org.jdsm.flow.core.users.IUser;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;


/**
 * User: Michael Komarichin aka mikom
 * Date: 13.06.2010
 * Time: 13:53:50
 */
public interface IUserDao<T> extends IGenericDao<IUser, T> {

/*    static List<IUser> EMPTY_USERS_SET = new ArrayList<IUser>();
    static List<IRole> EMPTY_ROLES_SET = new ArrayList<IRole>();
    static List<IGroup> EMPTY_GROUPS_SET = new ArrayList<IGroup>();*/

    /**
     * find user entity by id. if we can't find entity then the method will return null
     *
     * @param identifier user id
     * @return null if can't found user
     */
    IUser findUserById(T identifier);

    /**
     * load user entity. param user have to contains id property. {@link org.jdsm.flow.core.base.IEntity}
     * method will return null if user can't be found by id property
     *
     * @param user user object not contain all data
     * @return null if can't found user
     */
    IUser loadUser(IUser user);

    /**
     * load all user roles. if user hasn't access any role the method will return empty set
     *
     * @param identifier user identifier
     * @return user roles  {@link org.jdsm.flow.core.users.IRole} or empty list
     */
    Collection<IRole> findUserRolesByUserId(T identifier);


    /**
     * load all user groups. if user hasn't access any group the method will return empty set as result
     *
     * @param identifier user identifier
     * @return empty set or user groups {@link IGroup}
     */
    Collection<IGroup> findUserGroupsByUserId(T identifier);


    /**
     * find role entity by id. if we can't find entity then the method will return null
     *
     * @param id role identifier
     * @return null if can't found role by id
     */
    IRole findRoleById(T id);

    /**
     * load role entity. param role have to contains id property. {@link org.jdsm.flow.core.base.IEntity}
     * method will return null if role can't be found by id property
     *
     * @param role role entity
     * @return null if can't found role
     */
    IRole loadRole(IRole role);

    /**
     * load all users which has access to role. If no user found method returns empty set
     *
     * @param role role object
     * @return list of users {@link IUser} or empty list
     */
    Collection<IUser> findUsersForRole(IRole role);


    /**
     * find group entity by id. if we can't find entity then the method will return null
     *
     * @param id group identifier
     * @return founded group
     */
    IGroup findGroupById(T id);

    /**
     * load group entity. param group have to contains id property. {@link org.jdsm.flow.core.base.IEntity}
     * method will return null if user can't be found by id property
     *
     * @param group group object
     * @return founded group or null if can't found
     */
    IGroup loadGroup(IGroup group);

    /**
     * load all users which has access to group. If no user found method returns empty set
     *
     * @param group group object
     * @return list of users {@link IUser} or empty list
     */
    Collection<IUser> findUsersForGroup(IGroup group);


    /**
     * load users entities by criteria
     *
     * @param maxResult   limit return result
     * @param startResult start value from result
     * @param isSort      is sort result by field
     * @param field       field for sorting result
     * @return list of users or empty list
     */
    Collection<IUser> loadUsersByCriteria(int maxResult, int startResult, boolean isSort, String field);

    /**
     * load groups entities by criteria
     *
     * @param maxResult   limit return result
     * @param startResult start value from result
     * @param isSort      is sort result by field
     * @param field       field for sorting result
     * @return list of groups or empty list
     */
    Collection<IGroup> loadGroupsByCriteria(int maxResult, int startResult, boolean isSort, String field);

    /**
     * load roles entities by criteria
     *
     * @param maxResult   limit return result
     * @param startResult start value from result
     * @param isSort      is sort result by field
     * @param field       field for sorting result
     * @return list of roles or empty list
     */
    Collection<IRole> loadRolesByCriteria(int maxResult, int startResult, boolean isSort, String field);

    /**
     * delete user entity
     *
     * @param id user identifier
     * @return removed user
     */
    IUser removeUser(T id);


    /**
     * delete role entity
     *
     * @param id role identifier
     * @return removed role
     */
    IRole removeRole(T id);


    /**
     * delete group entity
     *
     * @param id group identifier
     * @return removed group
     */
    IGroup removeGroup(T id);


    /**
     * include user to roles or add user permission
     *
     * @param user    user
     * @param roleIds roles
     */
    void includeUserToRoles(IUser user, Collection<T> roleIds);

    /**
     * include user to groups or add user permission
     *
     * @param user     user
     * @param groupIds set of group id
     */
    void includeUserToGroups(IUser user, Collection<T> groupIds);

    /**
     * exclude user from roles
     *
     * @param user  user
     * @param roles set of roles for excluding user
     */
    void excludeUserFromRoles(IUser user, Collection<T> roles);

    /**
     * exclude user from group
     *
     * @param user   user
     * @param groups set of groups for excluding user
     */
    void excludeUserFromGroups(IUser user, Collection<T> groups);


    /**
     * save or update user
     *
     * @param user user
     * @return saved user or null if user object can't was saved
     */
    IUser saveOrUpdate(IUser user);

    /**
     * save or update role
     *
     * @param role role
     * @return saved role or null if role object can't was saved
     */
    IRole saveOrUpdate(IRole role);

    /**
     * save or update group
     *
     * @param group group
     * @return saved group or null if group object can't was saved
     */
    IGroup saveOrUpdate(IGroup group);

    /**
     * if permission < than permission of groups in db, return value will be empty list
     *
     * @param permission permission
     * @return list of group or empty list
     */
    Collection<IGroup> findAllowedGroups(Long permission);

    /**
     * if permission < than permission of groups in db, return value will be empty list
     *
     * @param permission permission
     * @return list of role or empty list
     */
    Collection<IRole> findAllowedRoles(Long permission);

    /**
     * can user access to group
     *
     * @param user  user
     * @param group group
     * @return true if user has access to group
     */
    boolean isAllowedUserAccess(IUser user, IGroup group);

    /**
     * can user access to role
     *
     * @param user user
     * @param role role
     * @return true if user has access to role
     */
    boolean isAllowedUserAccess(IUser user, IRole role);

    /**
     * find user entity by name {@link org.jdsm.flow.core.users.IUser#getName()}
     *
     * @param name user name
     * @return user {@link IUser}
     */
    IUser findUserByName(String name);

    /**
     * find user entity by nickname {@link org.jdsm.flow.core.users.IUser#getNickName()}
     *
     * @param nickName user nick name
     * @return user {@link IUser}
     */
    IUser findUserByNickName(String nickName);

    /**
     * find role entity by name {@link org.jdsm.flow.core.users.IRole#getName()}
     *
     * @param name role name
     * @return role {@link IRole}
     */
    IRole findRoleByName(String name);

    /**
     * find group entity by name {@link org.jdsm.flow.core.users.IGroup#getName()}
     *
     * @param name group name
     * @return group {@link IGroup}
     */
    IGroup findGroupByName(String name);


    /**
     * @return count of users
     */
    int usersCount();

    /**
     * @return count of roles
     */
    int rolesCount();

    /**
     * @return count of groups
     */
    int groupCount();

    /**
     * @return blank user object
     */
    IUser newUserInstance();

    /**
     * @return blank role entity
     */
    IRole newRoleInstance();

    /**
     * @return blank group entity
     */
    IGroup newGroupInstance();

    /**
     * {@link #includeUserToRoles(org.jdsm.flow.core.users.IUser, java.util.Collection)}
     *
     * @param user  user entity
     * @param roles set of roles
     */
    void enableUserToRoles(IUser user, Collection<IRole> roles);

    /**
     * {@link #excludeUserFromRoles(org.jdsm.flow.core.users.IUser, java.util.Collection)}
     *
     * @param user  user
     * @param roles set or roles
     */
    void disableUserFromRoles(IUser user, Collection<IRole> roles);

    /**
     * {@link #includeUserToGroups(org.jdsm.flow.core.users.IUser, java.util.Collection)}
     *
     * @param user   user entity
     * @param groups set of group
     */
    void enableUserToGroups(IUser user, Collection<IGroup> groups);

    /**
     * {@link #excludeUserFromGroups(org.jdsm.flow.core.users.IUser, java.util.Collection)}
     *
     * @param user   user entity
     * @param groups set of group
     */
    void disableUserFromGroups(IUser user, Collection<IGroup> groups);

    /**
     * change user roles
     *
     * @param user  user entity
     * @param roles new user roles
     */
    void reassignUserRoles(IUser user, Collection<IRole> roles);

    /**
     * change user group
     *
     * @param user   user entity
     * @param groups set of new user group
     */
    void reassignUserGroups(IUser user, Collection<IGroup> groups);

    /**
     * change user role by role's ids
     *
     * @param user    user entity
     * @param roleIds set of new id role's
     */
    void reassignUserRoleById(IUser user, Collection<T> roleIds);

    /**
     * change user group by group's ids
     *
     * @param user     user entity
     * @param groupIds set of new id group's
     */
    void reassignUserGroupById(IUser user, Collection<T> groupIds);

    /**
     * find max permission for user
     * @param user user entity
     * @return max permission(min value as long)
     */
    Long findUserMaxPermissionByRole(IUser user);

    /**
     * checking is user has access to roles passed by collection ids of roles
     * @param user user entity
     * @param roles collection ids of roles
     * @return true if user has access
     */
    boolean hasUserAccessToRolesId(IUser user, Collection<T> roles);

    /**
     * checking is user has access to roles passed by collection names of roles
     * @param user user entity
     * @param rolesName collection names of roles
     * @return true if user has access
     */
    boolean hasUserAccessToRolesByName(IUser user, Collection<String> rolesName);

    /**
     * checking is user has access to roles
     * @param user user entity
     * @param roles collection of roles
     * @return true if user has access
     */
    boolean hasUserAccessToRoles(IUser user, Collection<IRole> roles);

    /**
     * checking is user has access to groups was passed by collection names of groups
     * @param user user entity
     * @param groupsName collection names of groups
     * @return true if user has access
     */
    boolean hasUserAccessToGroupByName(IUser user, Collection<String> groupsName);

    /**
     * checking is user has access to groups
     * @param user       user entity
     * @param groups collection of groups
     * @return true if user has access
     */
    boolean hasUserAccessToGroups(IUser user, Collection<IGroup> groups);

    /**
     * save or find role instance
     * @param roleName role name
     * @param permission permission of role
     * @return instance of role
     */
    public IRole newRoleInstance(String roleName, Long permission);

    /**
     * save or find group instance
     * @param groupName group name
     * @param permission permission of group
     * @return instance of group
     */
    public IGroup newGroupInstance(String groupName, Long permission);

    /**
     * chenage user name
     * @param user user entity
     * @param newUserName new user name
     */
    void setUserName(IUser user, String newUserName);

    /**
     * change user password
     * @param user user entity
     * @param password new user password
     */
    void setPassword(IUser user, String password);

    /**
     * change user hint
     * @param user user entity
     * @param hint new user hint
     */
    void setHint(IUser user, String hint);

    /**
     * change user nick name
     * @param user user entity
     * @param nickName new user nick name
     */
    void setNickName(IUser user, String nickName);
}
